使用带有 lenient = true 设置的 Gson RuntimeTypeAdapterFactory
Use Gson RuntimeTypeAdapterFactory with lenient = true setting
我们摄取 returns 一些格式错误的 JSON 的 API(特别是 Double.NaN
被序列化为 String
和 "NaN")。
为了允许此 gson 始终将 lenient
设置为 true 并将其正确序列化回 Double.NaN
.
现在,我们想使用 gson-extras 中的 RuntimeTypeAdapterFactory
class 来删除一些样板代码。
刚刚描述的行为不再适用于此,我们收到消息
java.lang.NumberFormatException: JSON forbids NaN and infinities: NaN
哪个
由于通常从 gson 设置的 lenient
选项,应该被忽略。
考虑这个小例子:
class Base
{
String type;
double malformedField;
}
class A extends Base{}
class B extends Base{}
我们使用 type
字段来确定我们想要哪个子class,因为当然否则我们无法推断出正确的类型。
这是我们用来创建子classes 和反序列化的设置:
RuntimeTypeAdapterFactory<Base> adapterFactory = RuntimeTypeAdapterFactory.of(Base.class, "type", true)
.registerSubtype(A.class, "A")
.registerSubtype(B.class, "B");
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(adapterFactory)
//.setLenient() // Has no effect at all
.create();
String json = "{\"type\":\"A\", \"malformedField\": \"NaN\"}";
Base a = gson.fromJson(json, Base.class); // throws said Exception
RuntimeTypeAdapterFactory
中的实施:
检查 RuntimeTypeAdapterFactory
中的代码后,我注意到 lenient
选项从未设置为 true,因为我们调用了 com.google.gson.TypeAdapter
的 fromJsonTree
方法,在我们创建了一个新的 JsonTreeReader
而无法更改 lenient
选项。
public final T fromJsonTree(JsonElement jsonTree) {
try {
JsonReader jsonReader = new JsonTreeReader(jsonTree);
return read(jsonReader);
} catch (IOException e) {
throw new JsonIOException(e);
}
}
我尝试通过调试手动将其设置为 true
,这似乎按预期工作(没有
NumberFormatException
并使用指定类型正确反序列化对象)。
现在的问题是:关于为什么我们不能在此处使用 lenient
选项,我是否遗漏了什么?乍一看,这似乎是 gson-extras 的错误,但我不确定。
这不完全是 gson-extras
的错误,因为 com.google.gson.TypeAdapter
class 来自核心库。我建议再注册一个 TypeAdapterFactory
并为所有 JsonReader
个实例强制 lenient
:
class AlwaysLenientTypeAdapterFactory implements TypeAdapterFactory {
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
return createCustomTypeAdapter(delegate);
}
private <T> TypeAdapter<T> createCustomTypeAdapter(TypeAdapter<T> delegate) {
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
in.setLenient(true);
return delegate.read(in);
}
};
}
}
用法:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(adapterFactory)
.registerTypeAdapterFactory(new AlwaysLenientTypeAdapterFactory())
.create();
另请参阅:
我们摄取 returns 一些格式错误的 JSON 的 API(特别是 Double.NaN
被序列化为 String
和 "NaN")。
为了允许此 gson 始终将 lenient
设置为 true 并将其正确序列化回 Double.NaN
.
现在,我们想使用 gson-extras 中的 RuntimeTypeAdapterFactory
class 来删除一些样板代码。
刚刚描述的行为不再适用于此,我们收到消息
java.lang.NumberFormatException: JSON forbids NaN and infinities: NaN
哪个
由于通常从 gson 设置的 lenient
选项,应该被忽略。
考虑这个小例子:
class Base
{
String type;
double malformedField;
}
class A extends Base{}
class B extends Base{}
我们使用 type
字段来确定我们想要哪个子class,因为当然否则我们无法推断出正确的类型。
这是我们用来创建子classes 和反序列化的设置:
RuntimeTypeAdapterFactory<Base> adapterFactory = RuntimeTypeAdapterFactory.of(Base.class, "type", true)
.registerSubtype(A.class, "A")
.registerSubtype(B.class, "B");
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(adapterFactory)
//.setLenient() // Has no effect at all
.create();
String json = "{\"type\":\"A\", \"malformedField\": \"NaN\"}";
Base a = gson.fromJson(json, Base.class); // throws said Exception
RuntimeTypeAdapterFactory
中的实施:
检查 RuntimeTypeAdapterFactory
中的代码后,我注意到 lenient
选项从未设置为 true,因为我们调用了 com.google.gson.TypeAdapter
的 fromJsonTree
方法,在我们创建了一个新的 JsonTreeReader
而无法更改 lenient
选项。
public final T fromJsonTree(JsonElement jsonTree) {
try {
JsonReader jsonReader = new JsonTreeReader(jsonTree);
return read(jsonReader);
} catch (IOException e) {
throw new JsonIOException(e);
}
}
我尝试通过调试手动将其设置为 true
,这似乎按预期工作(没有
NumberFormatException
并使用指定类型正确反序列化对象)。
现在的问题是:关于为什么我们不能在此处使用 lenient
选项,我是否遗漏了什么?乍一看,这似乎是 gson-extras 的错误,但我不确定。
这不完全是 gson-extras
的错误,因为 com.google.gson.TypeAdapter
class 来自核心库。我建议再注册一个 TypeAdapterFactory
并为所有 JsonReader
个实例强制 lenient
:
class AlwaysLenientTypeAdapterFactory implements TypeAdapterFactory {
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
return createCustomTypeAdapter(delegate);
}
private <T> TypeAdapter<T> createCustomTypeAdapter(TypeAdapter<T> delegate) {
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
in.setLenient(true);
return delegate.read(in);
}
};
}
}
用法:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(adapterFactory)
.registerTypeAdapterFactory(new AlwaysLenientTypeAdapterFactory())
.create();
另请参阅: